use std::collections::HashMap;

use common_base::{
    prelude::*,
    serde::{self, Deserialize},
};

use crate::{service_engine::service_model::ServiceContainer, support::DylibRepository};

use super::{
    service_component_stub::ServiceComponentStub,
    service_context_builder_stub::ServiceContextBuilderStub,
};

#[derive(Deserialize, Debug)]
#[serde(crate = "self::serde")]
#[serde(rename_all = "camelCase")]
pub struct ServiceContainerStub {
    comp_creator: String,
    #[serde(rename = "iD")]
    id: String,
    name: String,
    stage_tran: i32,
    auto_commit: bool,
    scriptable: bool,
    #[serde(rename = "needDBConnection")]
    need_db_connection: bool,
    finish_before_commit: bool,
    property_map: HashMap<String, String>,

    service_context_builder_stub: ServiceContextBuilderStub,

    before_prepare_comp: bool,
    prepare_service: Option<String>,
    finish_service: Option<String>,

    prepare_service_component_stub: Option<ServiceComponentStub>,
    process_service_component_stub: Option<ServiceComponentStub>,
    finish_service_component_stub: Option<ServiceComponentStub>,
}

impl ServiceContainerStub {
    pub fn generate_service_container(
        self,
        dylib_repository: &DylibRepository,
    ) -> Result<ServiceContainer> {
        debug_assert!(self.comp_creator.eq("ServiceContainer"));

        let service_context_builder = self
            .service_context_builder_stub
            .load_service_context_builder(dylib_repository)?;
        let prepare_service_component = if let Some(stub) = self.prepare_service_component_stub {
            Some(stub.load_service_component(dylib_repository)?)
        } else {
            None
        };
        let process_service_component = if let Some(stub) = self.process_service_component_stub {
            Some(stub.load_service_component(dylib_repository)?)
        } else {
            None
        };
        let finish_service_component = if let Some(stub) = self.finish_service_component_stub {
            Some(stub.load_service_component(dylib_repository)?)
        } else {
            None
        };

        Ok(ServiceContainer::new(
            self.id,
            self.name,
            self.stage_tran,
            self.auto_commit,
            self.scriptable,
            self.need_db_connection,
            self.finish_before_commit,
            self.property_map,
            service_context_builder,
            self.before_prepare_comp,
            self.prepare_service,
            prepare_service_component,
            process_service_component,
            finish_service_component,
            self.finish_service,
        ))
    }
}
